#!/bin/bash

: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
: ${OVN_CTL_DEFAULT="/usr/share/ovn/scripts/ovn-ctl"}
: ${NB_MASTER_PORT_DEFAULT="6641"}
: ${NB_MASTER_PROTO_DEFAULT="tcp"}
: ${SB_MASTER_PORT_DEFAULT="6642"}
: ${SB_MASTER_PROTO_DEFAULT="tcp"}
: ${MANAGE_NORTHD_DEFAULT="no"}
: ${INACTIVE_PROBE_DEFAULT="5000"}
: ${INACTIVE_PROBE_TO_MASTER_DEFAULT="60000"}
: ${LISTEN_ON_MASTER_IP_ONLY_DEFAULT="yes"}
: ${NB_SSL_KEY_DEFAULT="/etc/openvswitch/ovnnb-privkey.pem"}
: ${NB_SSL_CERT_DEFAULT="/etc/openvswitch/ovnnb-cert.pem"}
: ${NB_SSL_CACERT_DEFAULT="/etc/openvswitch/cacert.pem"}
: ${SB_SSL_KEY_DEFAULT="/etc/openvswitch/ovnsb-privkey.pem"}
: ${SB_SSL_CERT_DEFAULT="/etc/openvswitch/ovnsb-cert.pem"}
: ${SB_SSL_CACERT_DEFAULT="/etc/openvswitch/cacert.pem"}

CRM_MASTER="${HA_SBIN_DIR}/crm_master -l reboot"
CRM_ATTR_REPL_INFO="${HA_SBIN_DIR}/crm_attribute --type crm_config --name OVN_REPL_INFO -s ovn_ovsdb_master_server"
OVN_CTL=${OCF_RESKEY_ovn_ctl:-${OVN_CTL_DEFAULT}}
MASTER_IP=${OCF_RESKEY_master_ip}
NB_MASTER_PORT=${OCF_RESKEY_nb_master_port:-${NB_MASTER_PORT_DEFAULT}}
NB_MASTER_PROTO=${OCF_RESKEY_nb_master_protocol:-${NB_MASTER_PROTO_DEFAULT}}
SB_MASTER_PORT=${OCF_RESKEY_sb_master_port:-${SB_MASTER_PORT_DEFAULT}}
SB_MASTER_PROTO=${OCF_RESKEY_sb_master_protocol:-${SB_MASTER_PROTO_DEFAULT}}
MANAGE_NORTHD=${OCF_RESKEY_manage_northd:-${MANAGE_NORTHD_DEFAULT}}
INACTIVE_PROBE=${OCF_RESKEY_inactive_probe_interval:-${INACTIVE_PROBE_DEFAULT}}
INACTIVE_PROBE_TO_MASTER=${OCF_RESKEY_inactive_probe_interval_to_master:-${INACTIVE_PROBE_TO_MASTER_DEFAULT}}
NB_PRIVKEY=${OCF_RESKEY_ovn_nb_db_privkey:-${NB_SSL_KEY_DEFAULT}}
NB_CERT=${OCF_RESKEY_ovn_nb_db_cert:-${NB_SSL_CERT_DEFAULT}}
NB_CACERT=${OCF_RESKEY_ovn_nb_db_cacert:-${NB_SSL_CACERT_DEFAULT}}
SB_PRIVKEY=${OCF_RESKEY_ovn_sb_db_privkey:-${SB_SSL_KEY_DEFAULT}}
SB_CERT=${OCF_RESKEY_ovn_sb_db_cert:-${SB_SSL_CERT_DEFAULT}}
SB_CACERT=${OCF_RESKEY_ovn_sb_db_cacert:-${SB_SSL_CACERT_DEFAULT}}


# In order for pacemaker to work with LB, we can set LISTEN_ON_MASTER_IP_ONLY
# to false and pass LB vip IP while creating pcs resource.
LISTEN_ON_MASTER_IP_ONLY=${OCF_RESKEY_listen_on_master_ip_only:-${LISTEN_ON_MASTER_IP_ONLY_DEFAULT}}

# Invalid IP address is an address that can never exist in the network, as
# mentioned in rfc-5737. The ovsdb servers connects to this IP address till
# a master is promoted and the IPAddr2 resource is started.
INVALID_IP_ADDRESS=192.0.2.254

host_name=$(ocf_attribute_target)
if [ "x$host_name" = "x" ]; then
    # function ocf_attribute_target may not be available if the pacemaker
    # version is old. Fall back to ocf_local_nodename.
    host_name=$(ocf_local_nodename)
fi
: ${slave_score=5}
: ${master_score=10}

ovsdb_server_metadata() {
    cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="ovsdb-server">
  <version>1.0</version>

  <longdesc lang="en">
    This resource manages ovsdb-server.
  </longdesc>

  <shortdesc lang="en">
    Manages ovsdb-server.
  </shortdesc>

  <parameters>

  <parameter name="ovn_ctl" unique="1">
  <longdesc lang="en">
  Location to the ovn-ctl script file
  </longdesc>
  <shortdesc lang="en">ovn-ctl script</shortdesc>
  <content type="string" default="${OVN_CTL_DEFAULT}" />
  </parameter>

  <parameter name="master_ip" unique="1">
  <longdesc lang="en">
  The IP address resource which will be available on the master ovsdb server
  </longdesc>
  <shortdesc lang="en">master ip address</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="nb_master_port" unique="1">
  <longdesc lang="en">
  The port which the master Northbound database server is listening
  </longdesc>
  <shortdesc lang="en">master Northbound database port</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="nb_master_protocol" unique="1">
  <longdesc lang="en">
  The protocol which the master Northbound database server used, 'tcp' or 'ssl'.
  </longdesc>
  <shortdesc lang="en">master Northbound database protocol</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="sb_master_port" unique="1">
  <longdesc lang="en">
  The port which the master Southbound database server is listening
  </longdesc>
  <shortdesc lang="en">master Southbound database port</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="sb_master_protocol" unique="1">
  <longdesc lang="en">
  The protocol which the master Southbound database server used, 'tcp' or 'ssl'.
  </longdesc>
  <shortdesc lang="en">master Southbound database protocol</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="manage_northd" unique="1">
  <longdesc lang="en">
  If set to yes, manages ovn-northd service. ovn-northd will be started in
  the master node.
  </longdesc>
  <shortdesc lang="en">manage ovn-northd service</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="inactive_probe_interval" unique="1">
  <longdesc lang="en">
  Inactive probe interval to set for ovsdb-server.
  </longdesc>
  <shortdesc lang="en">Set inactive probe interval</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="inactive_probe_interval_to_master" unique="1">
  <longdesc lang="en">
  Inactive probe interval to use for the connection from standby
  ovsdb-server to master ovsdb-server.
  </longdesc>
  <shortdesc lang="en">Set inactive probe interval to master</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="listen_on_master_ip_only" unique="1">
  <longdesc lang="en">
  If set to yes, the OVNDBs will listen on master IP. Otherwise, it will
  listen on 0.0.0.0. Set to yes when using pacemaker managed vip resource
  as MASTER_IP; set to no when using external LB VIP.
  </longdesc>
  <shortdesc lang="en">Listen on master IP or 0.0.0.0</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="ovn_nb_db_privkey" unique="1">
  <longdesc lang="en">
  OVN NB DB private key absolute path for ssl setup.
  </longdesc>
  <shortdesc lang="en">OVN NB DB private key file</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="ovn_nb_db_cert" unique="1">
  <longdesc lang="en">
  OVN NB DB certificate absolute path for ssl setup.
  </longdesc>
  <shortdesc lang="en">OVN NB DB cert file</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="ovn_nb_db_cacert" unique="1">
  <longdesc lang="en">
  OVN NB DB CA certificate absolute path for ssl setup.
  </longdesc>
  <shortdesc lang="en">OVN NB DB cacert file</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="ovn_sb_db_privkey" unique="1">
  <longdesc lang="en">
  OVN SB DB private key absolute path for ssl setup.
  </longdesc>
  <shortdesc lang="en">OVN SB DB private key file</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="ovn_sb_db_cert" unique="1">
  <longdesc lang="en">
  OVN SB DB certificate absolute path for ssl setup.
  </longdesc>
  <shortdesc lang="en">OVN SB DB cert file</shortdesc>
  <content type="string" />
  </parameter>

  <parameter name="ovn_sb_db_cacert" unique="1">
  <longdesc lang="en">
  OVN SB DB CA certificate absolute path for ssl setup.
  </longdesc>
  <shortdesc lang="en">OVN SB DB cacert file</shortdesc>
  <content type="string" />
  </parameter>

  </parameters>

  <actions>
    <action name="notify"       timeout="20s" />
    <action name="start"        timeout="30s" />
    <action name="stop"         timeout="20s" />
    <action name="promote"      timeout="50s" />
    <action name="demote"       timeout="50s" />
    <action name="monitor"      timeout="20s"  depth="0" interval="10s"
     role="Master" />
    <action name="monitor"      timeout="20s"  depth="0" interval="30s"
     role="Slave"/>
    <action name="meta-data"    timeout="5s" />
    <action name="validate-all" timeout="20s" />
  </actions>
</resource-agent>
END
    exit $OCF_SUCCESS
}

ovsdb_server_notify() {
    # requires the notify=true meta resource attribute
    local type_op="${OCF_RESKEY_CRM_meta_notify_type}-${OCF_RESKEY_CRM_meta_notify_operation}"

    if [ "$type_op" != "post-promote" ]; then
        # We are only interested in specific events
        return $OCF_SUCCESS
    fi

    ocf_log debug "ovndb_server: notified of event $type_op"
    if [ "x$(ovsdb_server_last_known_master)" = "x${host_name}" ]; then
        # Record ourselves so that the agent has a better chance of doing
        # the right thing at startup
        ocf_log debug "ovndb_server: $host_name is the master"
        ${CRM_ATTR_REPL_INFO} -v "$host_name"
        if [ "$MANAGE_NORTHD" = "yes" ]; then
            # Startup ovn-northd service
            ${OVN_CTL} --ovn-manage-ovsdb=no start_northd
        fi

        # In order to over-ride inactivity_probe for LB use case, we need to
        # create connection entry to listen on 0.0.0.0 for master node.
        if [ "x${LISTEN_ON_MASTER_IP_ONLY}" = xno ]; then
           LISTEN_ON_IP="0.0.0.0"
        else
           # ovn-[sn]bctl want ':[]' characters to be escaped. We do so in
           # order to make this work when MASTER_IP is an IPv6 address.
           LISTEN_ON_IP=$(sed -e 's/\(\[\|\]\|:\)/\\\1/g' <<< ${MASTER_IP})
        fi
        conn=`ovn-nbctl get NB_global . connections`
        if [ "$conn" == "[]" ]
        then
            ovn-nbctl -- --id=@conn_uuid create Connection \
target="p${NB_MASTER_PROTO}\:${NB_MASTER_PORT}\:${LISTEN_ON_IP}" \
inactivity_probe=$INACTIVE_PROBE -- set NB_Global . connections=@conn_uuid
        else
            CONN_UID=$(sed -e 's/^\[//' -e 's/\]$//' <<< ${conn})
            ovn-nbctl set connection "${CONN_UID}" target="p${NB_MASTER_PROTO}\:${NB_MASTER_PORT}\:${LISTEN_ON_IP}"
        fi

        conn=`ovn-sbctl get SB_global . connections`
        if [ "$conn" == "[]" ]
        then
            ovn-sbctl -- --id=@conn_uuid create Connection \
target="p${SB_MASTER_PROTO}\:${SB_MASTER_PORT}\:${LISTEN_ON_IP}" \
inactivity_probe=$INACTIVE_PROBE -- set SB_Global . connections=@conn_uuid
        else
            CONN_UID=$(sed -e 's/^\[//' -e 's/\]$//' <<< ${conn})
            ovn-sbctl set connection "${CONN_UID}" target="p${SB_MASTER_PROTO}\:${SB_MASTER_PORT}\:${LISTEN_ON_IP}"
        fi

    else
        if [ "$MANAGE_NORTHD" = "yes" ]; then
            # Stop ovn-northd service. Set --ovn-manage-ovsdb=no so that
            # ovn-ctl doesn't stop ovsdb-servers.
            ${OVN_CTL} --ovn-manage-ovsdb=no stop_northd
        fi
        # Synchronize with the new master
        ocf_log debug "ovndb_server: Connecting to the new master ${OCF_RESKEY_CRM_meta_notify_promote_uname}"
        ${OVN_CTL} demote_ovnnb --db-nb-sync-from-addr=${MASTER_IP} \
                                --db-nb-sync-from-port=${NB_MASTER_PORT} \
                                --db-nb-sync-from-proto=${NB_MASTER_PROTO} \
                                --db-nb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER}
        ${OVN_CTL} demote_ovnsb --db-sb-sync-from-addr=${MASTER_IP} \
                                --db-sb-sync-from-port=${SB_MASTER_PORT} \
                                --db-sb-sync-from-proto=${SB_MASTER_PROTO} \
                                --db-sb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER}
    fi
}

ovsdb_server_usage() {
    cat <<END
usage: $0 {start|stop|status|monitor|notify|validate-all|meta-data}

Expects to have a fully populated OCF RA-compliant environment set.
END
    exit $1
}

ovsdb_server_find_active_master() {
    # Operation sequence is Demote -> Stop -> Start -> Promote
    # At the point this is run, the only active masters will be
    # previous masters minus any that were scheduled to be demoted

    for master in ${OCF_RESKEY_CRM_meta_notify_master_uname}; do
        found=0
        for old in ${OCF_RESKEY_CRM_meta_notify_demote_uname}; do
            if [ $master = $old ]; then
                found=1
            fi
        done
        if [ $found = 0 ]; then
            # Rely on master-max=1
            # Pacemaker will demote any additional ones it finds before starting new copies
            echo "$master"
            return
        fi
    done

    local expected_master=$($CRM_ATTR_REPL_INFO --query  -q 2>/dev/null)
    case "x${OCF_RESKEY_CRM_meta_notify_start_uname}x" in
        *${expected_master}*) echo "${expected_master}";; # The previous master is expected to start
    esac
}

ovsdb_server_last_known_master()
{
    if [ -z "$MASTER_HOST" ]; then
        MASTER_HOST="$(${CRM_ATTR_REPL_INFO} --query  -q  2>/dev/null)"
    fi
    echo "$MASTER_HOST"
}

ovsdb_server_master_update() {
    case $1 in
        $OCF_SUCCESS)
        $CRM_MASTER -N $host_name -v ${slave_score};;
        $OCF_RUNNING_MASTER)
            $CRM_MASTER -N $host_name -v ${master_score};;
        #*) $CRM_MASTER -D;;
    esac
}

ovsdb_server_monitor() {
    ovsdb_server_check_status $@
    rc=$?

    ovsdb_server_master_update $rc
    return $rc
}

ovsdb_server_check_status() {
    local sb_status=`${OVN_CTL} status_ovnsb`
    local nb_status=`${OVN_CTL} status_ovnnb`

    if [[ $sb_status == "running/backup" && $nb_status == "running/backup" ]]; then
        return $OCF_SUCCESS
    fi

    check_northd="no"
    if [ "$MANAGE_NORTHD" == "yes" ] && [ "$1" != "ignore_northd" ]; then
        check_northd="yes"
    fi

    if [[ $sb_status == "running/active" && $nb_status == "running/active" ]]; then
        if [ "$check_northd" == "yes" ]; then
            # Verify if ovn-northd is running or not.
            ${OVN_CTL} status_northd
            if [ "$?" == "0" ] ; then
                return $OCF_RUNNING_MASTER
            fi
        else
            return $OCF_RUNNING_MASTER
        fi
    fi

    # TODO: What about service running but not in either state above?
    # Eg. a transient state where one db is "active" and the other
    # "backup"

    return $OCF_NOT_RUNNING
}

ovsdb_server_start() {
    ovsdb_server_check_status
    local status=$?
    # If not in stopped state, return
    if [ $status -ne $OCF_NOT_RUNNING ]; then
        return $status
    fi

    local present_master=$(ovsdb_server_find_active_master)

    set ${OVN_CTL}

    if [ "x${LISTEN_ON_MASTER_IP_ONLY}" = xno ]; then
        set $@ --db-nb-port=${NB_MASTER_PORT}
        set $@ --db-sb-port=${SB_MASTER_PORT}

    else
       set $@ --db-nb-addr=${MASTER_IP} --db-nb-port=${NB_MASTER_PORT}
       set $@ --db-sb-addr=${MASTER_IP} --db-sb-port=${SB_MASTER_PORT}
    fi

    if [ "x${NB_MASTER_PROTO}" = xssl ]; then
            set $@ --ovn-nb-db-ssl-key=${NB_PRIVKEY}
            set $@ --ovn-nb-db-ssl-cert=${NB_CERT}
            set $@ --ovn-nb-db-ssl-ca-cert=${NB_CACERT}
    fi
    if [ "x${SB_MASTER_PROTO}" = xssl ]; then
            set $@ --ovn-sb-db-ssl-key=${SB_PRIVKEY}
            set $@ --ovn-sb-db-ssl-cert=${SB_CERT}
            set $@ --ovn-sb-db-ssl-ca-cert=${SB_CACERT}
    fi
    if [ "x${present_master}" = x ]; then
        # No master detected, or the previous master is not among the
        # set starting.
        #
        # Force all copies to come up as slaves by pointing them into
        # space and let pacemaker pick one to promote:
        #
        if [ "x${NB_MASTER_PROTO}" = xtcp ]; then
            set $@ --db-nb-create-insecure-remote=yes
        fi

        if [ "x${SB_MASTER_PROTO}" = xtcp ]; then
            set $@ --db-sb-create-insecure-remote=yes
        fi
        set $@ --db-nb-sync-from-addr=${INVALID_IP_ADDRESS} --db-sb-sync-from-addr=${INVALID_IP_ADDRESS}

    elif [ ${present_master} != ${host_name} ]; then
        if [ "x${LISTEN_ON_MASTER_IP_ONLY}" = xyes ]; then
            if [ "x${NB_MASTER_PROTO}" = xtcp ]; then
                set $@ --db-nb-create-insecure-remote=yes
            fi

            if [ "x${SB_MASTER_PROTO}" = xtcp ]; then
                set $@ --db-sb-create-insecure-remote=yes
            fi
        fi
        # An existing master is active, connect to it
        set $@ --db-nb-sync-from-addr=${MASTER_IP} --db-sb-sync-from-addr=${MASTER_IP}
        set $@ --db-nb-sync-from-port=${NB_MASTER_PORT}
        set $@ --db-nb-sync-from-proto=${NB_MASTER_PROTO}
        set $@ --db-sb-sync-from-port=${SB_MASTER_PORT}
        set $@ --db-sb-sync-from-proto=${SB_MASTER_PROTO}
        if [ "x${LISTEN_ON_MASTER_IP_ONLY}" = xno ]; then
            set $@ --db-sb-use-remote-in-db="no"
            set $@ --db-nb-use-remote-in-db="no"
        fi
    fi

    $@ start_ovsdb

    while [ 1 = 1 ]; do
        # It is important that we don't return until we're in a functional
        # state. When checking the status of the ovsdb-server's ignore northd.
        # It is possible that when the resource is restarted ovsdb-server's
        # can be started as masters and ovn-northd would not have been started.
        # ovn-northd will be started once a node is promoted to master and
        # 'manage_northd' is set to yes.
        ovsdb_server_monitor ignore_northd
        rc=$?
        case $rc in
            $OCF_SUCCESS)        return $rc;;
            $OCF_RUNNING_MASTER)
                # When a slave node is promoted as master, the action would be
                # STOP -> START -> PROMOTE.
                # When the start action is called, it is possible for the
                # ovsdb-server's to be started as active. This could happen
                # if the node owns the $MASTER_IP. At this point, pacemaker
                # has not promoted this node yet. Demote it and check for
                # status again.
                # Let pacemaker promote it in subsequent actions.
                # As per the OCF guidelines, only monitor action should return
                # OCF_RUNNING_MASTER.
                # http://www.linux-ha.org/doc/dev-guides/_literal_ocf_running_master_literal_8.html
                ${OVN_CTL} demote_ovnnb \
                --db-nb-sync-from-addr=${INVALID_IP_ADDRESS}
                ${OVN_CTL} demote_ovnsb \
                --db-sb-sync-from-addr=${INVALID_IP_ADDRESS}
                ;;
            $OCF_ERR_GENERIC)    return $rc;;
            # Otherwise loop, waiting for the service to start, until
            # the cluster times the operation out
        esac
        ocf_log warn "ovndb_servers: After starting ovsdb, status is $rc. Checking the status again"
    done
}

ovsdb_server_stop() {
    if [ "$MANAGE_NORTHD" = "yes" ]; then
        # Stop ovn-northd service in case it was running. This is required
        # when the master is demoted. For other cases, it would be a no-op.
        # Set --ovn-manage-ovsdb=no so that ovn-ctl doesn't stop ovsdb-servers.
        ${OVN_CTL} --ovn-manage-ovsdb=no stop_northd
    fi

    ovsdb_server_check_status ignore_northd
    case $? in
        $OCF_NOT_RUNNING)
          # Even if one server is down, check_status returns NOT_RUNNING.
          # So before returning call stop_ovsdb to be sure.
          ${OVN_CTL} stop_ovsdb
          return ${OCF_SUCCESS};;
    esac

    ${OVN_CTL} stop_ovsdb
    ovsdb_server_master_update ${OCF_NOT_RUNNING}

    while [ 1 = 1 ]; do
        # It is important that we don't return until we're stopped
        ovsdb_server_check_status ignore_northd
        rc=$?
        case $rc in
        $OCF_SUCCESS)
            # Loop, waiting for the service to stop, until the
            # cluster times the operation out
            ocf_log warn "ovndb_servers: Even after stopping, the servers seems to be running"
            ;;
        $OCF_NOT_RUNNING)
            return $OCF_SUCCESS
            ;;
        *)
            return $rc
            ;;
        esac
    done

    return $OCF_ERR_GENERIC
}

ovsdb_server_promote() {
    local state

    ovsdb_server_check_status ignore_northd
    rc=$?
    case $rc in
        ${OCF_SUCCESS}) ;;
        ${OCF_RUNNING_MASTER}) ;;
        *)
            ovsdb_server_master_update $OCF_RUNNING_MASTER
            return ${rc}
            ;;
    esac

    # Restart ovs so that new master can listen on tcp port
    if [ "x${LISTEN_ON_MASTER_IP_ONLY}" = xno ]; then
        ${OVN_CTL} stop_ovsdb
        ovsdb_server_start
    fi
    ${OVN_CTL} promote_ovnnb
    ${OVN_CTL} promote_ovnsb

    if [ "$MANAGE_NORTHD" = "yes" ]; then
        # Startup ovn-northd service
        ${OVN_CTL} --ovn-manage-ovsdb=no start_northd
    fi

    ocf_log debug "ovndb_servers: Waiting for promotion $host_name as master to complete"
    ovsdb_server_check_status
    state=$?
    while [ "$state" != "$OCF_RUNNING_MASTER" ]; do
      sleep 1
      ovsdb_server_check_status
      state=$?
    done
    ocf_log debug "ovndb_servers: Promotion of $host_name as the master completed"
    # Record ourselves so that the agent has a better chance of doing
    # the right thing at startup
    ${CRM_ATTR_REPL_INFO} -v "$host_name"
    ovsdb_server_master_update $OCF_RUNNING_MASTER
    return $OCF_SUCCESS
}

ovsdb_server_demote() {
    # While demoting, check the status of ovn_northd.
    # In case ovn_northd is not running, we should return OCF_NOT_RUNNING.
    ovsdb_server_check_status
    if [ $? = $OCF_NOT_RUNNING ]; then
        return $OCF_NOT_RUNNING
    fi

    local present_master=$(ovsdb_server_find_active_master)
    local recorded_master=$($CRM_ATTR_REPL_INFO --query  -q 2>/dev/null)

    ocf_log debug "ovndb_servers: Demoting $host_name, present master ${present_master}, recorded master ${recorded_master}"
    if [ "x${recorded_master}" = "x${host_name}" -a "x${present_master}" = x ]; then
        # We are the one and only master
        # This should be the "normal" case
        # The only way to be demoted is to call demote_ovn*
        #
        # The local database is only reset once we successfully
        # connect to the peer.  So specify one that doesn't exist.
        #
        # Eventually a new master will be promoted and we'll resync
        # using the logic in ovsdb_server_notify()
        ${OVN_CTL} demote_ovnnb --db-nb-sync-from-addr=${INVALID_IP_ADDRESS}
        ${OVN_CTL} demote_ovnsb --db-sb-sync-from-addr=${INVALID_IP_ADDRESS}

    elif [ "x${present_master}" = "x${host_name}" ]; then
        # Safety check, should never be called
        #
        # Never allow sync'ing from ourselves, its a great way to
        # erase the local DB
        ${OVN_CTL} demote_ovnnb --db-nb-sync-from-addr=${INVALID_IP_ADDRESS}
        ${OVN_CTL} demote_ovnsb --db-sb-sync-from-addr=${INVALID_IP_ADDRESS}

    elif [ "x${present_master}" != x ]; then
        # There are too many masters and we're an extra one that is
        # being demoted. Sync to the surviving one
        ${OVN_CTL} demote_ovnnb --db-nb-sync-from-addr=${MASTER_IP} \
                                --db-nb-sync-from-port=${NB_MASTER_PORT} \
                                --db-nb-sync-from-proto=${NB_MASTER_PROTO} \
                                --db-nb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER}
        ${OVN_CTL} demote_ovnsb --db-sb-sync-from-addr=${MASTER_IP} \
                                --db-sb-sync-from-port=${SB_MASTER_PORT} \
                                --db-sb-sync-from-proto=${SB_MASTER_PROTO} \
                                --db-sb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER}

    else
        # For completeness, should never be called
        #
        # Something unexpected happened, perhaps CRM_ATTR_REPL_INFO is incorrect
        ${OVN_CTL} demote_ovnnb --db-nb-sync-from-addr=${INVALID_IP_ADDRESS}
        ${OVN_CTL} demote_ovnsb --db-sb-sync-from-addr=${INVALID_IP_ADDRESS}
    fi

    if [ "$MANAGE_NORTHD" = "yes" ]; then
        # Stop ovn-northd service
        ${OVN_CTL} --ovn-manage-ovsdb=no stop_northd
    fi
    ovsdb_server_master_update $OCF_SUCCESS
    return $OCF_SUCCESS
}

ovsdb_server_validate() {
    if [ ! -e ${OVN_CTL} ]; then
        return $OCF_ERR_INSTALLED
    fi
    return $OCF_SUCCESS
}


case $__OCF_ACTION in
start)          ovsdb_server_start;;
stop)           ovsdb_server_stop;;
promote)        ovsdb_server_promote;;
demote)         ovsdb_server_demote;;
notify)         ovsdb_server_notify;;
meta-data)      ovsdb_server_metadata;;
validate-all)   ovsdb_server_validate;;
status|monitor) ovsdb_server_monitor;;
usage|help)     ovsdb_server_usage $OCF_SUCCESS;;
*)              ovsdb_server_usage $OCF_ERR_UNIMPLEMENTED ;;
esac

rc=$?
exit $rc
